# -*- coding: utf-8 -*-
"""
战斗系统统一消息协议定义

本文件定义了所有服务器间（Django后端、Node.js战斗服务器）和页面间（前端、Cocos客户端）的通讯数据格式。
所有消息处理都应该遵循这里定义的格式，避免各处自作主张定义格式。
"""

from typing import Dict, Any, Optional, List, Union, Type, TypeVar
from dataclasses import dataclass, field
from enum import Enum
import json
import logging
from datetime import datetime

logger = logging.getLogger(__name__)
T = TypeVar('T', bound='BaseMessage')


class MessageType(Enum):
    """消息类型枚举"""
    # 基础通讯
    READY = "ready"                    # iframe准备就绪
    PING = "ping"                      # 心跳检测
    PONG = "pong"                      # 心跳响应
    
    # 命令相关
    COMMAND = "command"                # 游戏命令（纯转发）
    COMMAND_VALIDATED = "command_validated"  # 命令验证结果
    
    # 战斗管理（服务器只关心配置和结果）
    BATTLE_INIT = "battle_init"        # 战斗初始化（传递配置参数）
    BATTLE_END = "battle_end"          # 战斗结束（接收结果和统计）
    
    # 错误处理
    ERROR = "error"                    # 错误消息
    
    @classmethod
    def is_valid(cls, value: str) -> bool:
        """检查消息类型是否有效"""
        return value in [item.value for item in cls]
    
    @classmethod
    def get_all_types(cls) -> List[str]:
        """获取所有消息类型"""
        return [item.value for item in cls]





class MessageValidationError(Exception):
    """消息验证异常"""
    pass


@dataclass
class BaseMessage:
    """基础消息格式"""
    type: str
    timestamp: Optional[str] = field(default_factory=lambda: datetime.now().isoformat())
    
    def __post_init__(self):
        """验证消息类型"""
        if not MessageType.is_valid(self.type):
            raise MessageValidationError(f"无效的消息类型: {self.type}")
    
    def to_dict(self) -> Dict[str, Any]:
        """转换为字典格式"""
        return {
            'type': self.type,
            'timestamp': self.timestamp
        }
    
    def to_json(self) -> str:
        """转换为JSON字符串"""
        try:
            return json.dumps(self.to_dict(), ensure_ascii=False)
        except Exception as e:
            logger.error(f"消息序列化失败: {e}")
            raise MessageValidationError(f"消息序列化失败: {e}")
    
    @classmethod
    def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
        """从字典创建消息对象"""
        try:
            return cls(**data)
        except Exception as e:
            logger.error(f"消息反序列化失败: {e}")
            raise MessageValidationError(f"消息反序列化失败: {e}")
    
    def validate(self) -> bool:
        """验证消息格式"""
        return True  # 基类默认验证通过，子类可重写


@dataclass
class CommandMessage(BaseMessage):
    """命令消息格式（纯转发，不解析内容）"""
    command_id: str = ""
    command_data: Dict[str, Any] = field(default_factory=dict)  # 原始命令数据，服务器只转发不解析
    user_id: Optional[int] = None
    username: Optional[str] = None
    
    def __post_init__(self):
        super().__post_init__()
        if not self.command_id:
            raise MessageValidationError("command_id不能为空")
        if not isinstance(self.command_data, dict):
            raise MessageValidationError("command_data必须是字典类型")
    
    def to_dict(self) -> Dict[str, Any]:
        result = super().to_dict()
        result.update({
            'command_id': self.command_id,
            'command_data': self.command_data
        })
        if self.user_id is not None:
            result['user_id'] = self.user_id
        if self.username:
            result['username'] = self.username
        return result
    
    def validate(self) -> bool:
        """验证命令消息格式"""
        if not super().validate():
            return False
        if not self.command_id or not isinstance(self.command_id, str):
            return False
        if not isinstance(self.command_data, dict):
            return False
        return True


@dataclass
class CommandValidationMessage(BaseMessage):
    """命令验证结果消息"""
    command_id: str = ""
    valid: bool = False
    message: str = ""
    
    def __post_init__(self):
        super().__post_init__()
        if not self.command_id:
            raise MessageValidationError("command_id不能为空")
    
    def to_dict(self) -> Dict[str, Any]:
        result = super().to_dict()
        result.update({
            'command_id': self.command_id,
            'valid': self.valid,
            'message': self.message
        })
        return result
    
    def validate(self) -> bool:
        """验证命令验证消息格式"""
        if not super().validate():
            return False
        if not self.command_id or not isinstance(self.command_id, str):
            return False
        if not isinstance(self.valid, bool):
            return False
        return True


@dataclass
class BattleStateMessage(BaseMessage):
    """战斗管理消息（仅用于初始化配置和结束结果）"""
    battle_id: str = ""
    state_data: Dict[str, Any] = field(default_factory=dict)  # 配置参数或结果统计数据
    
    def __post_init__(self):
        super().__post_init__()
        if not self.battle_id:
            raise MessageValidationError("battle_id不能为空")
        if not isinstance(self.state_data, dict):
            raise MessageValidationError("state_data必须是字典类型")
    
    def to_dict(self) -> Dict[str, Any]:
        result = super().to_dict()
        result.update({
            'battle_id': self.battle_id,
            'state_data': self.state_data
        })
        return result
    
    def validate(self) -> bool:
        """验证战斗状态消息格式"""
        if not super().validate():
            return False
        if not self.battle_id or not isinstance(self.battle_id, str):
            return False
        if not isinstance(self.state_data, dict):
            return False
        return True





@dataclass
class ErrorMessage(BaseMessage):
    """错误消息"""
    error_code: str = ""
    error_message: str = ""
    details: Optional[Dict[str, Any]] = None
    
    def __post_init__(self):
        super().__post_init__()
        if not self.error_code:
            raise MessageValidationError("error_code不能为空")
        if not self.error_message:
            raise MessageValidationError("error_message不能为空")
    
    def to_dict(self) -> Dict[str, Any]:
        result = super().to_dict()
        result.update({
            'error_code': self.error_code,
            'error_message': self.error_message
        })
        if self.details:
            result['details'] = self.details
        return result
    
    def validate(self) -> bool:
        """验证错误消息格式"""
        if not super().validate():
            return False
        if not self.error_code or not isinstance(self.error_code, str):
            return False
        if not self.error_message or not isinstance(self.error_message, str):
            return False
        return True


class MessageProtocol:
    """消息协议工具类"""
    
    @staticmethod
    def create_command_message(command_id: str, command_data: Dict[str, Any], 
                             user_id: Optional[int] = None, username: Optional[str] = None) -> Dict[str, Any]:
        """创建命令消息"""
        try:
            msg = CommandMessage(
                type=MessageType.COMMAND.value,
                command_id=command_id,
                command_data=command_data,
                user_id=user_id,
                username=username
            )
            return msg.to_dict()
        except Exception as e:
            logger.error(f"创建命令消息失败: {e}")
            raise MessageValidationError(f"创建命令消息失败: {e}")
    
    @staticmethod
    def create_command_validation_message(command_id: str, valid: bool, message: str) -> Dict[str, Any]:
        """创建命令验证结果消息"""
        try:
            msg = CommandValidationMessage(
                type=MessageType.COMMAND_VALIDATED.value,
                command_id=command_id,
                valid=valid,
                message=message
            )
            return msg.to_dict()
        except Exception as e:
            logger.error(f"创建命令验证消息失败: {e}")
            raise MessageValidationError(f"创建命令验证消息失败: {e}")
    
    @staticmethod
    def create_battle_state_message(message_type: str, battle_id: str, state_data: Dict[str, Any]) -> Dict[str, Any]:
        """创建战斗管理消息（仅用于BATTLE_INIT和BATTLE_END）"""
        try:
            # 验证消息类型
            if message_type not in [MessageType.BATTLE_INIT.value, MessageType.BATTLE_END.value]:
                raise MessageValidationError(f"无效的战斗消息类型: {message_type}")
            
            msg = BattleStateMessage(
                type=message_type,
                battle_id=battle_id,
                state_data=state_data
            )
            return msg.to_dict()
        except Exception as e:
            logger.error(f"创建战斗状态消息失败: {e}")
            raise MessageValidationError(f"创建战斗状态消息失败: {e}")
    
    @staticmethod
    def create_error_message(error_code: str, error_message: str, 
                           details: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """创建错误消息"""
        try:
            msg = ErrorMessage(
                type=MessageType.ERROR.value,
                error_code=error_code,
                error_message=error_message,
                details=details
            )
            return msg.to_dict()
        except Exception as e:
            logger.error(f"创建错误消息失败: {e}")
            raise MessageValidationError(f"创建错误消息失败: {e}")
    
    @staticmethod
    def parse_message(data: Union[str, Dict[str, Any]]) -> BaseMessage:
        """解析消息数据"""
        try:
            # 如果是字符串，先解析为字典
            if isinstance(data, str):
                data = json.loads(data)
            
            if not isinstance(data, dict):
                raise MessageValidationError("消息数据必须是字典或JSON字符串")
            
            message_type = data.get('type')
            if not message_type:
                raise MessageValidationError("消息缺少type字段")
            
            # 根据消息类型创建相应的消息对象
            if message_type == MessageType.COMMAND.value:
                return CommandMessage.from_dict(data)
            elif message_type == MessageType.COMMAND_VALIDATED.value:
                return CommandValidationMessage.from_dict(data)
            elif message_type in [MessageType.BATTLE_INIT.value, MessageType.BATTLE_END.value]:
                return BattleStateMessage.from_dict(data)
            elif message_type == MessageType.ERROR.value:
                return ErrorMessage.from_dict(data)
            else:
                # 对于其他类型，返回基础消息
                return BaseMessage.from_dict(data)
                
        except json.JSONDecodeError as e:
            logger.error(f"JSON解析失败: {e}")
            raise MessageValidationError(f"JSON解析失败: {e}")
        except Exception as e:
            logger.error(f"消息解析失败: {e}")
            raise MessageValidationError(f"消息解析失败: {e}")
    
    @staticmethod
    def validate_message(data: Union[str, Dict[str, Any]]) -> bool:
        """验证消息格式"""
        try:
            message = MessageProtocol.parse_message(data)
            return message.validate()
        except Exception as e:
            logger.warning(f"消息验证失败: {e}")
            return False


# 常用消息格式示例
EXAMPLE_MESSAGES = {
    'command': {
        'type': 'command',
        'command_id': 'cmd_1234567890_abcdef',
        'command_data': {
            # 原始命令数据，服务器不解析，直接转发
            'action': 'move',
            'unit_id': 'unit_123',
            'target': {'x': 10, 'y': 20}
        },
        'user_id': 1,
        'username': 'player1'
    },

    'battle_init': {
        'type': 'battle_init',
        'battle_id': 'battle_123',
        'state_data': {
            # 战斗配置参数
            'round_limit': 100,
            'player1_info': {'user_id': 1, 'username': 'player1'},
            'player2_info': {'user_id': 2, 'username': 'player2'},
            'map_config': {'width': 20, 'height': 20}
        }
    },
    'battle_end': {
        'type': 'battle_end',
        'battle_id': 'battle_123',
        'state_data': {
            # 战斗结果和统计
            'winner': 'player1',
            'total_rounds': 45,
            'end_reason': 'victory',
            'statistics': {
                'player1_units_killed': 5,
                'player2_units_killed': 8
            }
        }
    }
}